package com.iflytek.jzcpx.procuracy.common.web;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

import com.iflytek.jzcpx.procuracy.common.enums.CommonResultEnum;
import com.iflytek.jzcpx.procuracy.common.exception.InvalidParameterException;
import com.iflytek.jzcpx.procuracy.common.exception.ViewException;
import com.iflytek.jzcpx.procuracy.common.result.Result;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Controller层统一异常处理类
 *
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2019/3/4 14:46
 */
@ControllerAdvice
public class ExpcetionHandler {
    private static final Logger logger = LoggerFactory.getLogger(ExpcetionHandler.class);

    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public Result<?> handleAllException(HttpServletRequest req, Throwable e) {
        StringBuffer requestURL = req.getRequestURL();
        String queryString = req.getQueryString();
        if (StringUtils.isNotBlank(queryString)) {
            requestURL.append("?").append(queryString);
        }
        logger.warn("Controller层请求异常, request: {} {}, exception: {}", req.getMethod(), requestURL, e.getMessage());

        if (e instanceof MethodArgumentNotValidException) {
            return buildInvalidArgumentResponse((MethodArgumentNotValidException) e);
        }
        else if (e instanceof InvalidParameterException) {
            return buildInvalidArgumentResponse((InvalidParameterException) e);
        }
        else if (e instanceof MissingServletRequestParameterException) {
            return buildMissServletParamResponse((MissingServletRequestParameterException) e);
        }
        else if (e instanceof ViewException) {
            return buildCustomErrorResponse((ViewException) e);
        }

        logger.error("Controller层抛出未知异常", e);
        String errorMsg = e.getMessage();
        return Result.failed(CommonResultEnum.FAILED, errorMsg);
    }

    /** 接口必填参数缺少 */
    private Result<?> buildMissServletParamResponse(MissingServletRequestParameterException e) {
        return Result.failed(CommonResultEnum.PARAMETER_MISSING, e.getMessage());
    }

    /** 业务异常 */
    private Result<?> buildCustomErrorResponse(ViewException e) {
        logger.warn("Controller层抛出业务异常.", e);
        return new Result<>(e.getResultType());
    }

    /** 自定义参数验证未通过 */
    private Result<?> buildInvalidArgumentResponse(InvalidParameterException e) {
        return new Result<>(e.getResultType());
    }

    /** SpringMVC 参数验证未通过 */
    private Result<?> buildInvalidArgumentResponse(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        if (bindingResult == null) {
            return new Result<>(CommonResultEnum.INVALID_PARAMETER);
        }

        List<FieldError> errorList = bindingResult.getFieldErrors();
        if (CollectionUtils.isEmpty(errorList)) {
            return new Result<>(CommonResultEnum.INVALID_PARAMETER);
        }

        String errorMessages = errorList.stream().map(error -> {
            String defaultMessage = error.getDefaultMessage();
            String field = error.getField();
            return defaultMessage.contains(field) ? defaultMessage : field + defaultMessage;
        }).filter(StringUtils::isNotBlank)
                                        .collect(Collectors.joining("; "));
        return Result.failed(CommonResultEnum.INVALID_PARAMETER, errorMessages);
    }

}
